package client;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


/*********************************************************************************************************
 * Downloads specified file to specified location asynchronously by connecting to sharing client
 * Server Socket and requesting the file according to protocol
 * @author Kim Persson
 ********************************************************************************************************/
public class DownloadFile extends Thread
{
	private String filename, ip,path;
	private int port, size, current;

	
	/***
	 * Default constructor
	 * @param path where to save file on computer
	 * @param filename name of file
	 * @param size how many bytes to download
	 * @param ip address to client sharing the file
	 * @param port port to connect to
	 */
	public DownloadFile(String path, String filename, int size,String ip, int port)
	{
		this.filename = filename;
		this.ip = ip;
		this.port = port;
		this.size = size;
		this.path = path;
		current = 0;
	}
	/***
	 * Gets download progress
	 * @return int representing progress in %
	 */
	public int getDownloadProgress()
	{
		long tempCurrent = (long)current;
		long result = (100*tempCurrent)/((long)size);
		return (int)result;
	}
	
	/**
	 * Gets filename of file it is downloading
	 * @return String with filename
	 */
	public String getFileName()
	{
		return filename;
	}
	
	/**
	 * Gets size in byte of file being downloaded
	 * @return file size in bytes
	 */
	public int getSize()
	{
		return size;
	}
	
	/**
	 * Downloads specified file to specified location asynchronously by connecting to sharing client
	 */
	public void run()
	{
		Socket s = null;
		try {
			long time = System.currentTimeMillis();
			System.out.println("Connecting to " + ip + ":" + port + " and downloading " + filename);
			s = new Socket(ip,port);
			PrintWriter pw = new PrintWriter(s.getOutputStream());
			pw.println("request#"+filename);
			pw.flush();
			
			File file = new File(path, filename);
			int tmp = 1;
			// Rename if duplicate until available name is found
			while(file.exists())
			{
				file = new File(path , "(" +  tmp +")" + filename);
				tmp++;
			}
			FileOutputStream fos  = new FileOutputStream(file);
			BufferedOutputStream bos = new BufferedOutputStream(fos);
			InputStream is = s.getInputStream();
			BufferedInputStream bis = new BufferedInputStream(is);
			
			while(bis.available() == 0)
				Thread.yield();

			int count;
			byte[] buffer = new byte[8192];
			while ((count = bis.read(buffer)) > 0)
			{
			  bos.write(buffer, 0, count);
			  current += count;
			}

			bos.flush();
			bos.close();
			pw.close();
			bis.close();

			
			System.out.println(filename + " successfully downloaded to " +  path + " in " + (System.currentTimeMillis() - time) + " ms");
		} catch (UnknownHostException e) {
			System.out.println("ERROR: Can't connect to host " + e.getMessage());

		} catch (IOException e) {
			if (e instanceof FileNotFoundException)
			{
				System.out.println("ERROR: Invalid path specified " + path + " aborting download...");
			} else
			{
				System.out.println("ERROR: " + e.getMessage() + " aborting download...");
			}
		} finally
		{
			try {
				s.close();
			} catch (IOException e) {
				System.out.println("ERROR: Failed to close Socket " + e.getMessage());
			}
		}

	}
	
}